﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace RFIDLIB
{
    public partial class RfidControl: UserControl
    {
        public delegate void DelegateTabsCallback(object sender, RFIDEventArgs e);
        public event DelegateTabsCallback TabsEvent;
        public string Connstr { get; set; }
        public UIntPtr hreader;
        public UIntPtr hTag;

        public byte enableAFI = 0;
        public byte AFI = 0;
        public byte onlyNewTag;
        public bool _shouldStop;
        public byte openState;
        public byte inventoryState;

        public byte[] AntennaSel = new byte[16];
        public byte AntennaSelCount = 0;
        public ArrayList airInterfaceProtList = new ArrayList();

        Thread InvenThread;
        private delegate void delegateInventoryFinishCallback();

        public void InventoryFinishCallback()
        {
            inventoryState = 0;
        }

        public delegate void delegate_tag_report_handle(uint AIPType, uint tagType, uint antID, byte[] uid, int uidlen);
        public RfidControl()
        {
            InitializeComponent();
        }

        public int Tag_inventory(
                               byte AIType,
                                 byte AntennaSelCount,
                                 byte[] AntennaSel,
                                bool enable15693,
                                bool enable14443A,
                                bool enable18000p3m3,
                                  byte enableAFI,
                                 byte afiVal,
                                delegate_tag_report_handle tagReportHandler,
                                 ref uint nTagCount)
        {

            int iret;
            UIntPtr InvenParamSpecList = UIntPtr.Zero;
            InvenParamSpecList = RFIDLIB.rfidlib_reader.RDR_CreateInvenParamSpecList();
            if (InvenParamSpecList.ToUInt64() != 0)
            {
                if (enable15693 == true)
                {
                    RFIDLIB.rfidlib_aip_iso15693.ISO15693_CreateInvenParam(InvenParamSpecList, 0, enableAFI, AFI, 0);
                }
            }
            nTagCount = 0;
        LABEL_TAG_INVENTORY:
            iret = RFIDLIB.rfidlib_reader.RDR_TagInventory(hreader, AIType, AntennaSelCount, AntennaSel, InvenParamSpecList);
            if (iret == 0 || iret == -21)
            {
                nTagCount += RFIDLIB.rfidlib_reader.RDR_GetTagDataReportCount(hreader);
                UIntPtr TagDataReport;
                TagDataReport = (UIntPtr)0;
                TagDataReport = RFIDLIB.rfidlib_reader.RDR_GetTagDataReport(hreader, RFIDLIB.rfidlib_def.RFID_SEEK_FIRST); //first
                while (TagDataReport.ToUInt64() > 0)
                {
                    uint aip_id = 0;
                    uint tag_id = 0;
                    uint ant_id = 0;
                    byte dsfid = 0;
                    byte uidlen = 0;
                    byte[] uid = new byte[16];

                    if (enable15693 == true)
                    {
                        iret = RFIDLIB.rfidlib_aip_iso15693.ISO15693_ParseTagDataReport(TagDataReport, ref aip_id, ref tag_id, ref ant_id, ref dsfid, uid);
                        if (iret == 0)
                        {
                            uidlen = 8;
                            object[] pList = { aip_id, tag_id, ant_id, uid, (int)uidlen };
                            Invoke(tagReportHandler, pList);
                        }
                    }
                    TagDataReport = RFIDLIB.rfidlib_reader.RDR_GetTagDataReport(hreader, RFIDLIB.rfidlib_def.RFID_SEEK_NEXT);
                }
                if (iret == -21)
                {
                    AIType = RFIDLIB.rfidlib_def.AI_TYPE_CONTINUE;
                    goto LABEL_TAG_INVENTORY;
                }
                iret = 0;
            }
            if (InvenParamSpecList.ToUInt64() != 0) RFIDLIB.rfidlib_data_node.DNODE_Destroy(InvenParamSpecList);
            return iret;
        }

        public void DoInventory()
        {
            bool enISO15693, enISO14443a, enISO18000p3m3;
            delegate_tag_report_handle cbTagReportHandle;

            cbTagReportHandle = new delegate_tag_report_handle(Dele_tag_report_handler);
            enISO15693 = enISO14443a = enISO18000p3m3 = false;
            for (int i = 0; i < airInterfaceProtList.Count; i++)
            {
                CSupportedAirProtocol aip;
                aip = (CSupportedAirProtocol)airInterfaceProtList[i];
                if (aip.m_en)
                {
                    if (aip.m_ID == RFIDLIB.rfidlib_def.RFID_APL_ISO15693_ID)
                    { 
                        enISO15693 = true;
                    }
                    else if (aip.m_ID == RFIDLIB.rfidlib_def.RFID_APL_ISO14443A_ID)
                    {
                        enISO14443a = true;
                    }
                   
                }
            }
            int iret;
            byte AIType = RFIDLIB.rfidlib_def.AI_TYPE_NEW;
            if (onlyNewTag == 1)
            {
                AIType = RFIDLIB.rfidlib_def.AI_TYPE_CONTINUE;  //only new tag inventory 
            }
            while (!_shouldStop)
            {

                uint nTagCount = 0;
                iret = Tag_inventory(AIType, AntennaSelCount, AntennaSel, enISO15693, enISO14443a, enISO18000p3m3, enableAFI, AFI, cbTagReportHandle, ref nTagCount);
                if (iret == 0)
                {
                    // inventory ok

                }
                else
                {
                    // inventory error 
                }
                AIType = RFIDLIB.rfidlib_def.AI_TYPE_NEW;
                if (onlyNewTag == 1)
                {
                    AIType = RFIDLIB.rfidlib_def.AI_TYPE_CONTINUE;  //only new tag inventory 
                }
            }
            object[] pFinishList = { };
            Invoke(new delegateInventoryFinishCallback(InventoryFinishCallback), pFinishList);
            RFIDLIB.rfidlib_reader.RDR_ResetCommuImmeTimeout(hreader);

        }

        private void Dele_tag_report_handler(uint AIPType, uint tagType, uint antID, byte[] uid, int uidlen)
        {

            //int nSize=0;
            //byte[] rd = null;
            ReadTabsData(uid, out byte[] rd, out int nSize);
            var e = new RFIDEventArgs
            {
                UID = BitConverter.ToString(uid,0,uidlen).Replace("-", string.Empty),
                Data = rd,
                DataLenght = nSize
                
            };
            TabsEvent(this, e);
        }

        public void Open()
        {
            int iret = 0;
            uint antennaCount = 0;
            RFIDLIB.rfidlib_reader.RDR_LoadReaderDrivers("");
            iret = RFIDLIB.rfidlib_reader.RDR_Open(Connstr, ref hreader);
            if (iret != 0)
            {
                MessageBox.Show("fail"+iret);
            }
            else
            {
                antennaCount = RFIDLIB.rfidlib_reader.RDR_GetAntennaInterfaceCount(hreader);
                uint index = 0;
                uint AIType;
                while (true)
                {
                    AIType = 0;
                    iret = RFIDLIB.rfidlib_reader.RDR_GetSupportedAirInterfaceProtocol(hreader, index, ref AIType);
                    if (iret != 0)
                    {
                        break;
                    }
                    StringBuilder namebuf = new StringBuilder();
                    namebuf.Append('\0', 128);
                    RFIDLIB.rfidlib_reader.RDR_GetAirInterfaceProtName(hreader, AIType, namebuf, (uint)namebuf.Capacity);

                    CSupportedAirProtocol aip = new CSupportedAirProtocol
                    {
                        m_ID = AIType,
                        m_name = namebuf.ToString(),
                        m_en = true
                    };
                    airInterfaceProtList.Add(aip);
                    index++;
                }
                Beep();
                openState = 1;
                _shouldStop = false;
                InvenThread = new Thread(DoInventory);
                InvenThread.Start();
                inventoryState = 1;
            }
        }

        public void Close()
        {
            _shouldStop = true;
            RFIDLIB.rfidlib_reader.RDR_SetCommuImmeTimeout(hreader);
            Thread.Sleep(1000);

            int iret = 0;
            if (hTag != (UIntPtr)0)
            {
                iret = RFIDLIB.rfidlib_reader.RDR_DisconnectAllTags(hreader);
                hTag = (UIntPtr)0;
            }

            iret = RFIDLIB.rfidlib_reader.RDR_Close(hreader);
            if (iret == 0)
            {
                hreader = (UIntPtr)0;
                openState = 0;
            }

        }

        public void Beep()
        {
            byte bcount = 0;
            int rec = RFIDLIB.rfidlib_reader.RDR_GetOutputCount(hreader, ref bcount);
            if (rec == 0)
            {
                for (int i = 1; i <= (int)bcount; i++)
                {
                    Console.WriteLine(i);
                    StringBuilder bf = new StringBuilder();
                    bf.Append('\0', 64);
                    uint nSize = 0;
                    byte idxOut = (byte)i;
                    var ir = rfidlib_reader.RDR_GetOutputName(hreader, idxOut, bf, ref nSize);
                    Console.WriteLine(bf.ToString());
                    var hOutputOperations = RFIDLIB.rfidlib_reader.RDR_CreateSetOutputOperations();
                    if (hOutputOperations.ToUInt64() > 0)
                    {
                        RFIDLIB.rfidlib_reader.RDR_AddOneOutputOperation(hOutputOperations, idxOut, 3, 2, 1, 1);
                        RFIDLIB.rfidlib_reader.RDR_SetOutput(hreader, hOutputOperations);
                        RFIDLIB.rfidlib_data_node.DNODE_Destroy(hOutputOperations);
                    }
                }
            }
        }

        public string GetReaderInfor()
        {
            StringBuilder devInfo = new StringBuilder();
            devInfo.Append('\0', 128);
            uint nSize = 0;
            int result = RFIDLIB.rfidlib_reader.RDR_GetReaderInfor(hreader, 0, devInfo, ref nSize);
            if (result == 0) {
                return devInfo.ToString();
            }
            return null;
        }

        public List<Dictionary<string, string>> GetDriverInfoList() {
            var connStrList = new List<Dictionary<string, string>>();
            RFIDLIB.rfidlib_reader.RDR_LoadReaderDrivers("");
            ArrayList readerDriverInfoList=new ArrayList();
            uint nCount = RFIDLIB.rfidlib_reader.RDR_GetLoadedReaderDriverCount();
            for (int i = 0; i < (int)nCount; i++)
            {
                var driver = new CReaderDriverInf();
                StringBuilder strCatalog = new StringBuilder();
                strCatalog.Append('\0', 128);
                uint nSize =(uint)strCatalog.Capacity;
                RFIDLIB.rfidlib_reader.RDR_GetLoadedReaderDriverOpt((uint)i, RFIDLIB.rfidlib_def.LOADED_RDRDVR_OPT_CATALOG, strCatalog,ref nSize);
                driver.m_catalog = strCatalog.ToString();
                if (strCatalog.ToString().Equals(RFIDLIB.rfidlib_def.RDRDVR_TYPE_READER))
                {
                    StringBuilder strName = new StringBuilder();
                    strName.Append('\0', 128);
                    nSize = (uint)strName.Capacity;
                    RFIDLIB.rfidlib_reader.RDR_GetLoadedReaderDriverOpt((uint)i, RFIDLIB.rfidlib_def.LOADED_RDRDVR_OPT_NAME, strName,ref nSize);
                    driver.m_name = strName.ToString();
                    StringBuilder strProductType = new StringBuilder();
                    strProductType.Append('\0', 128);
                    nSize = (uint)strProductType.Capacity;
                    RFIDLIB.rfidlib_reader.RDR_GetLoadedReaderDriverOpt((uint)i, RFIDLIB.rfidlib_def.LOADED_RDRDVR_OPT_ID, strProductType,ref nSize);
                    driver.m_productType = strProductType.ToString();
                    StringBuilder strCommSupported = new StringBuilder();
                    strCommSupported.Append('\0', 128);
                    nSize = (uint)strCommSupported.Capacity;
                    RFIDLIB.rfidlib_reader.RDR_GetLoadedReaderDriverOpt((uint)i, RFIDLIB.rfidlib_def.LOADED_RDRDVR_OPT_COMMTYPESUPPORTED, strCommSupported,ref nSize);
                    driver.m_commTypeSupported = uint.Parse(strCommSupported.ToString());
                    readerDriverInfoList.Add(driver);
                }
            }
            for (int i = 0; i < readerDriverInfoList.Count; i++)
            {
                var drv = readerDriverInfoList[i] as CReaderDriverInf;
                if(drv.m_commTypeSupported == RFIDLIB.rfidlib_def.COMMTYPE_USB_EN)
                {
                    uint nUSBCnt = RFIDLIB.rfidlib_reader.HID_Enum(drv.m_name);
                    for (uint j = 0; j < nUSBCnt; j++)
                    {
                        StringBuilder SerialNumber = new StringBuilder();
                        SerialNumber.Append('\0', 128);
                        uint nSize =(uint) SerialNumber.Capacity;
                        RFIDLIB.rfidlib_reader.HID_GetEnumItem(j, RFIDLIB.rfidlib_def.HID_ENUM_INF_TYPE_SERIALNUM, SerialNumber, ref nSize);
                        var connStr = new Dictionary<string, string>
                        {
                            {
                                drv.m_name + "_" + SerialNumber.ToString(),
                                string.Format("RDType={0};CommType=USB;AddrMode=1;SerNum={1}",drv.m_name,SerialNumber.ToString())
                            }
                        };
                        connStrList.Add(connStr);
                    }
                }else if (drv.m_commTypeSupported == RFIDLIB.rfidlib_def.COMMTYPE_COM_EN)
                {
                    uint nCOMCnt = RFIDLIB.rfidlib_reader.COMPort_Enum();
                    for (uint j = 0; j < nCOMCnt; j++)
                    {
                        StringBuilder comName = new StringBuilder();
                        comName.Append('\0', 128);
                        uint nSize = (uint)comName.Capacity;
                        RFIDLIB.rfidlib_reader.COMPort_GetEnumItem(j, comName, nSize);
                        var connStr = new Dictionary<string, string>
                        {
                            {
                                drv.m_name + "_" + comName.ToString(),
                                string.Format("RDType={0};CommType=COM;COMName={1};BaudRate=38400;Frame=8E1;BusAddr=255",drv.m_name,comName.ToString())
                            }
                        };
                        connStrList.Add(connStr);
                    }
                }
            }
            return connStrList;
        }
        private byte[] ReadMultiBlocks(uint begin,uint count,ref int rSize)
        {
            int iret;
            byte dsfid = 0; byte fafi = 0; uint blkSize = 0; uint blkNum = 0; byte icref = 0;
            byte[] buid = new byte[8];
            iret = RFIDLIB.rfidlib_aip_iso15693.ISO15693_GetSystemInfo(hreader, hTag, buid, ref dsfid, ref fafi, ref blkSize, ref blkNum, ref icref);
            if (iret == 0)
            {
                if (count > blkNum) { count = blkNum; }
                int bitLength =(int)(blkSize * (count - begin));
                uint numOfBlksRead;
                uint bytesRead;
                byte[] bufBlocks = new byte[bitLength];
                uint nSize = (uint)bufBlocks.GetLength(0);
                numOfBlksRead = bytesRead = 0;
                iret = RFIDLIB.rfidlib_aip_iso15693.ISO15693_ReadMultiBlocks(hreader, hTag, 0, begin, count,ref numOfBlksRead, bufBlocks, nSize,ref bytesRead);
                if (iret == 0)
                {
                    rSize = (int)bytesRead;
                    return bufBlocks;
                }
            }
            return null;
        }
        private void ReadTabsData(byte[] uid,out byte[] rd,out int nSize)
        {
            nSize = 0;
            rd = null;
            int iret = RFIDLIB.rfidlib_aip_iso15693.ISO15693_Connect(hreader, RFIDLIB.rfidlib_def.RFID_ISO15693_PICC_ICODE_SLI_ID, 1, uid,ref hTag);
            if (iret == 0)
            {
                rd = ReadMultiBlocks(0, 2,ref nSize);
                iret = RFIDLIB.rfidlib_reader.RDR_TagDisconnect(hreader, hTag);
                if (iret == 0)
                {
                    hTag = (UIntPtr)0;
                }
            }
        }

        private void RfidControl_ControlAdded(object sender, ControlEventArgs e)
        {
            e.Control.Visible = false;
            this.Visible = false;
        }
    }
   

}
